use std::collections::HashMap;
use std::sync::{Arc, Mutex};

pub struct Cacher {
    executor:Arc<Mutex<Box<dyn FnMut(Vec<u8>) -> Vec<u8>>>>,
    inner:Vec<u8>
}

impl Cacher {
    pub fn new<F>(f:F) -> Cacher
        where F:FnMut(Vec<u8>) -> Vec<u8> +'static
    {
        Cacher{
            executor:Arc::new(Mutex::new(Box::new(f))),
            inner:Vec::new()
        }
    }

    pub fn exec(&mut self,data:Vec<u8>) -> Vec<u8> {
        (self.executor.lock().unwrap())(data)
    }
}

impl Clone for Cacher {
    fn clone(&self) -> Self {
        let f = self.executor.clone();
        let inner = self.inner.clone();

        Cacher{
            inner,
            executor:f,
        }
    }
}

#[cfg(test)]
mod test {
    use std::collections::HashMap;
    use std::sync::{Arc, Mutex};
    use crate::util::cacher::Cacher;

    pub struct test_struct {}

    impl test_struct {
        pub fn test(&mut self,data:Vec<u8>) -> Vec<u8> {
            data
        }

        pub fn test2(&mut self,data:Vec<u8>) -> Vec<u8> {
            println!("{:?}",data);
            data
        }
    }

    #[test]
    fn test () {
        let mut tt = Arc::new(Mutex::new(test_struct{}));
        let tt1 = tt.clone();
        let tt2 = tt.clone();
        let a = Cacher::new(move |data| {
            let mut new = tt1.lock().unwrap().test(data);
            new.push(8);
            new
        });
        let b =  Cacher::new(move |data| {
            let mut new = tt2.lock().unwrap().test(data);
            new.push(8);
            new.push(9);
            new
        });
        let mut d = HashMap::new();
        d.insert("1",a);
        d.insert("2",b);

        let aa= d.get_mut("1").unwrap().exec(vec![1,2,3,4]);
        println!("{:?}",aa);

        let vv= d.get_mut("2").unwrap().exec(vec![1,2,3,4,5]);
        println!("{:?}",vv);


    }
}